// 所有的方法在释放对象时，都需要手动释放
// simple factory 
typedef struct _Shoe
{
    int type;
    void (*print_shoe)(struct _Shoe*);
}Shoe;

void print_leather_shoe(struct _Shoe* pShoe)
{
    assert(NULL != pShoe);
    printf("This is a leather show!\n");
}
 
void print_rubber_shoe(struct _Shoe* pShoe)
{
    assert(NULL != pShoe);
    printf("This is a rubber shoe!\n");
}


#define LEATHER_TYPE 0x01
#define RUBBER_TYPE  0x02
// 鞋子工厂（用来生产鞋子），简单的，不符合开闭原则
Shoe* manufacture_new_shoe(int type)
{
    assert(LEATHER_TYPE == type || RUBBER_TYPE == type);
 
    Shoe* pShoe = (Shoe*)malloc(sizeof(Shoe));
    assert(NULL != pShoe);
 
    memset(pShoe, 0, sizeof(Shoe));
    if(LEATHER_TYPE == type)
    {
        pShoe->type == LEATHER_TYPE;
        pShoe->print_shoe = print_leather_shoe;
    }
    else
    {
        pShoe->type == RUBBER_TYPE;
        pShoe->print_shoe = print_rubber_shoe;
    }
 
    return pShoe;
}

// 下面是抽象工厂

typedef struct _Apple
{
    void (*print_apple)();
}Apple;
 
typedef struct _Grape
{
    void (*print_grape)();
}Grape; 

void print_white_apple()
{
    printf("white apple!\n");
}
 
void print_red_apple()
{
    printf("red apple!\n");
}
 
void print_white_grape()
{
    printf("white grape!\n");
}
 
void print_red_grape()
{
    printf("red grape!\n");
}

// 抽象的工厂方法
typedef struct _FruitShop
{
    Apple* (*sell_apple)();
    Apple* (*sell_grape)();
}FruitShop;

// 具体的工厂方法
Apple* sell_white_apple()
{
    Apple* pApple = (Apple*) malloc(sizeof(Apple));
    assert(NULL != pApple);
 
    pApple->print_apple = print_white_apple;
    return pApple;
}
 
Grape* sell_white_grape()
{
    Grape* pGrape = (Grape*) malloc(sizeof(Grape));
    assert(NULL != pGrape);
 
    pGrape->print_grape = print_white_grape;
    return pGrape;
} 

// 用来创建一个水果工厂
FruitShop* create_fruit_shop(int color)
{
    FruitShop* pFruitShop = (FruitShop*) malloc(sizeof(FruitShop));
    assert(NULL != pFruitShop);
 
    if(WHITE == color)
    {
        pFruitShop->sell_apple = sell_white_apple;
        pFruitShop->sell_grape = sell_white_grape;
    }
    else
    {
        pFruitShop->sell_apple = sell_red_apple;
        pFruitShop->sell_grape = sell_red_grape;
    }
 
    return pFruitShop;
}